package com.codi.api.controller.organ;

import com.codi.api.controller.BaseController;
import com.codi.api.security.UserUtil;
import com.codi.api.validation.OrganTradeValidation;
import com.codi.api.validation.TradeValidation;
import com.codi.base.exception.BaseAppException;
import com.codi.base.exception.ExceptionHandler;
import com.codi.base.log.annotation.Loggable;
import com.codi.base.util.EqualsUtil;
import com.codi.base.util.ListUtil;
import com.codi.base.util.StringUtil;
import com.codi.base.util.TimeUtil;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.dao.UserSessionDao;
import com.codi.bus.core.domain.Lookup;
import com.codi.bus.core.domain.User;
import com.codi.bus.core.domain.UserBank;
import com.codi.bus.core.domain.UserSession;
import com.codi.bus.core.resultModel.BaseResult;
import com.codi.bus.core.service.*;
import com.codi.bus.core.service.model.ShareTypeModel;
import com.codi.bus.core.service.organ.OrganTradeService;
import com.codi.bus.core.service.util.FundUtil;
import com.codi.bus.core.util.BaseResultUtil;
import com.codi.bus.core.vo.BuyVo;
import com.codi.bus.core.vo.OrganBuyVo;
import com.codi.bus.core.vo.OrganSellVo;
import com.codi.bus.util.LookupUtil;
import com.codi.message.constant.ErrorConst;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;

/**
 * 机构交易模块
 *
 * @author shi.pengyan
 * @version 1.0 2017-09-12 10:52
 * @since 1.0
 */
@Slf4j
@RestController
@RequestMapping("/organ/trade")
public class OrganTradeController extends BaseController {

    @Autowired
    private OrganTradeValidation organTradeValidation;

    @Autowired
    private QueryService queryService;

    @Autowired
    private TradeService tradeService;

    @Autowired
    private BankService bankService;

    @Autowired
    private TradeValidation tradeValidation;

    @Autowired
    private OrganTradeService organTradeService;

    @Autowired
    private UserSessionDao userSessionDao;

    @Autowired
    private UserService userService;

    @Autowired
    private LookupService lookupService;

    @Autowired
    private WalletService walletService;

    /**
     * 机构申购
     *  2018.6.5 不再使用
     * @param requestVo
     * @param token
     * @return
     */
    @Loggable
    @PostMapping("buy")
    public BaseResult buy(@Validated OrganBuyVo requestVo,
                          @RequestHeader(GlobalConstant.HEADER_AUTH_TOKEN) String token) throws BaseAppException {

        BaseResult result;

        String paymentType = GlobalConstant.CAPTIAL_MODE_K; //k
        if (!EqualsUtil.equals(paymentType, requestVo.getPaymentType())) {
            paymentType = GlobalConstant.CAPTIAL_MODE_K;
        }

        Integer moneyType = GlobalConstant.MONEY_TYPE_RMB;

        String bankAccount = "";

        Long userId = UserUtil.getLoginUserId();

        List<UserBank> userBanks = bankService.getListByUserId(userId);

        if (ListUtil.isEmpty(userBanks)) {
            log.error("userId={} has no banks, plz check", userId);
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
        }

        String requestBankAccount = requestVo.getBankAccount();

        if (StringUtils.isNotBlank(requestBankAccount)) {
            boolean isUserBank = false;
            for (int i = 0; i < userBanks.size(); i++) {
                UserBank bank = userBanks.get(i);
                if (StringUtils.equals(bank.getUserBankNo(), requestBankAccount)) {
                    isUserBank = true;
                    bankAccount = requestBankAccount;
                    break;
                }
            }

            if (!isUserBank) {
                log.error("传递的参数{}不是用户的银行卡", requestBankAccount);
                ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
            }

        } else {
            bankAccount = userBanks.get(0).getUserBankNo(); // 只取第一张银行卡
        }


        // 校验机构用户的开户状态
        result = organTradeValidation.validateOrganBuy(requestVo, bankAccount, paymentType, userId);
        if (result != null) {
            return result;
        }

        ShareTypeModel shareTypeModel = queryService.getShareType(requestVo.getFundCode());
        if (shareTypeModel == null || StringUtil.isEmpty(shareTypeModel.getShareType())) {
            result = new BaseResult();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND, null));
            return result;
        }

        // 获取份额类别
        String shareType = shareTypeModel.getShareType();
        // 调用接口
        result = tradeService.buy(userId, token, bankAccount, paymentType, moneyType,
            requestVo.getFundName(), requestVo.getFundCode(), requestVo.getFundBalance(),
            shareType, requestVo.getTradePassword(), requestVo.getApplyNo());

        if (result.getSuccess() == false && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }

        return result;
    }

    /**
     * 申购
     *  2018.6.5 开始使用
     * @param buyVo
     * @param deviceId
     * @return
     * @author zx
     * @date 2018-05-08 14:10:15
     */
    @Loggable
    @PostMapping("/buy/v2")
    @ResponseBody
    public BaseResult buy(@Validated BuyVo buyVo, String profileId,
                          @RequestHeader(value = GlobalConstant.HEADER_OS_TYPE) String deviceId) {
        Long userId = UserUtil.getLoginUserId();
        Long pId = Long.valueOf(profileId);
        buyVo.setUserId(userId);
        buyVo.setMoneyType(GlobalConstant.MONEY_TYPE_RMB);
        buyVo.setChannelId(deviceId);

        BaseResult result;

        // 验证输入
        result = tradeValidation.validateBuy(buyVo);
        if (result != null) {
            log.info("trade validation fail.");
            return result;
        }

        // 调用接口
        result = organTradeService.organBuy(buyVo,pId);

        BaseResultUtil.parseErrMsg(result);

        return result;
    }


    /**
     * 机构赎回
     * 2018.6.5 不再使用
     * @param requestVo
     * @param token
     */
    @Loggable
    @PostMapping(path = "sell38")
    public BaseResult sell(@Validated OrganSellVo requestVo, String profileId,
                           @RequestHeader(GlobalConstant.HEADER_AUTH_TOKEN) String token) {

        BaseResult result = null;
        Long pId = Long.valueOf(profileId);
        // 验证输入
        result = organTradeValidation.validateOrganSell(requestVo, UserUtil.getLoginUserId(),pId);
        if (result != null) {
            return result;
        }

        // 获取份额类别
        ShareTypeModel shareTypeModel = queryService.getShareType(requestVo.getFundCode());
        if (shareTypeModel == null || StringUtil.isEmpty(shareTypeModel.getShareType())) {
            result = new BaseResult();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND, null));
            return result;
        }

        // 获取份额类别
        String shareType = shareTypeModel.getShareType();


        // 调用接口
        result = tradeService.sell(UserUtil.getLoginUserId(), token,
            requestVo.getBankAccount(),
            requestVo.getPaymentType(),
            requestVo.getFundName(),
            requestVo.getFundCode(),
            requestVo.getShares(),
            shareType,
            requestVo.getTradePassword(),
            requestVo.getApplyNo());
        if (result.getSuccess() == false && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }

        return result;
    }

    /**
     * 机构赎回
     * 2018.6.5 开始使用
     * 新版加了新的字段
     * @param requestVo
     * @param token
     */
    @Loggable
    @PostMapping(path = "sell/v2")
    public BaseResult sellV2(@Validated OrganSellVo requestVo, String tradeAccount, String profileId,
                             @RequestHeader(GlobalConstant.HEADER_AUTH_TOKEN) String token) {

        BaseResult result = null;
        Long pId = Long.valueOf(profileId);
        // 验证输入
        result = organTradeValidation.validateOrganSell(requestVo, UserUtil.getLoginUserId(),pId);
        if (result != null) {
            return result;
        }

        // 获取份额类别
        ShareTypeModel shareTypeModel = queryService.getShareType(requestVo.getFundCode());
        if (shareTypeModel == null || StringUtil.isEmpty(shareTypeModel.getShareType())) {
            result = new BaseResult();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND, null));
            return result;
        }

        // 获取份额类别
        String shareType = shareTypeModel.getShareType();

        UserSession userSession = userSessionDao.getEntityByToken(token);

        // 判断Session是否存在
        if (userSession == null) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_LOGIN_IN_OTHER_PLACE);
            return result;
        }


        // 调用接口
        result = organTradeService.sell(UserUtil.getLoginUserId(), userSession.getChannelId(),
            requestVo.getBankAccount(),
            requestVo.getPaymentType(),
            requestVo.getFundName(),
            requestVo.getFundCode(),
            requestVo.getShares(),
            shareType,
            requestVo.getTradePassword(),
            requestVo.getApplyNo(),
            tradeAccount,
            pId);
        if (result.getSuccess() == false && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }

        return result;
    }



    /**
     * 快速赎回
     *
     * @param token         用户Token
     * @param bankAccount   银行账号
     * @param paymentType   支付方式
     * @param fundName      基金名称
     * @param fundCode      基金代码
     * @param shares        份额
     * @param tradeAcco     交易账号
     * @param tradePassword 交易密码
     * @param sign          签名
     * @param applyNo       申请编号
     * @param deviceId      设备ID
     *                      不再使用   机构没有快赎了
     */
    @Loggable
    @RequestMapping(value = "/fastRedeem", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<BaseResult> fastRedeem(@RequestParam String bankAccount,
                                                 @RequestParam String paymentType,
                                                 @RequestParam String fundName,
                                                 @RequestParam String fundCode,
                                                 @RequestParam BigDecimal shares,
                                                 @RequestParam String tradePassword,
                                                 @RequestParam String sign,
                                                 @RequestParam String applyNo,
                                                 @RequestParam String tradeAcco,
                                                 String profileId,
                                                 @RequestHeader(value = GlobalConstant.HEADER_APP_DEVICE) String deviceId,
                                                 @RequestHeader(value = GlobalConstant.HEADER_AUTH_TOKEN) String token) {

        BaseResult result = null;


        fundCode = fundCode.trim();

        String brandsType = FundUtil.getT0FundBrandsType(fundCode);

        Long pId = Long.valueOf(profileId);

        Long userId = UserUtil.getLoginUserId();

        User user = userService.getUser(userId);
        if (user.getIsOrg()) { // 机构

            if (lookupService.isT0Fund(fundCode)) {

                // 如果是机构用户，宝盈不支持快速赎回 shi.pengyan 2017-10-11 10:24:07
                if (FundUtil.isBaoYingT0AB(fundCode)) {
                    result = new BaseResult();
                    result.setSuccess(false)
                        .setErrorCode(ErrorConst.COMMON_USER_PERMISSION_ONLY)
                        .setErrorMessage(MessageUtil.getErrorMsg(ErrorConst.COMMON_USER_PERMISSION_ONLY));

                    return new ResponseEntity<>(result, HttpStatus.OK);
                }
                //如果是机构用户，金鹰T+0, 不支持快速赎回  zengxl 2018-04-20
                if (FundUtil.isJinYingT0AB(fundCode)) {
                    result = new BaseResult();
                    result.setSuccess(false)
                        .setErrorCode(ErrorConst.COMMON_USER_PERMISSION_ONLY)
                        .setErrorMessage(MessageUtil.getErrorMsg(ErrorConst.COMMON_USER_PERMISSION_ONLY));

                    return new ResponseEntity<>(result, HttpStatus.OK);
                }
                // 金鹰T+0, 机构快速赎回时间为每天8:35-17:00，其余时间只能进行普通赎回
                /*if (FundUtil.isJinYingT0AB(fundCode)) {

                    String startTimeStr = lookupService.getLookup(RuleConstant.T0FUND_JINYING_START_TIME).getRuleValue();
                    String endTimeStr   = lookupService.getLookup(RuleConstant.T0FUND_JINYING_END_TIME).getRuleValue();

                    Boolean isInRange = TimeUtil.nowIsInRange(startTimeStr + ":00", endTimeStr + ":00", TimeUtil.FORMAT_HHmmSS);

                    if (!isInRange) {
                        String errorMsg = MessageUtil.getErrorMsg(ErrorConst.ORGAN_FASTREDEEM_JINYING_NOT_IN_SUPPORT_TIME
                            , startTimeStr, endTimeStr);

                        result = new BaseResult();
                        result.setSuccess(false)
                              .setErrorCode(ErrorConst.ORGAN_FASTREDEEM_JINYING_NOT_IN_SUPPORT_TIME)
                              .setErrorMessage(errorMsg);

                        return new ResponseEntity<>(result, HttpStatus.OK);
                    }
                }*/

                // 长城T+0, 机构快速取现时间为9:00-16:45，其余时间只能进行普通赎回
                if (FundUtil.isChangChengT0AB(fundCode)) {

                    String startTimeStr = lookupService.getLookup(RuleConstant.T0FUND_CHANGCHENG_START_TIME).getRuleValue();
                    String endTimeStr   = lookupService.getLookup(RuleConstant.T0FUND_CHANGCHENG_END_TIME).getRuleValue();

                    Boolean isInRange = TimeUtil.nowIsInRange(startTimeStr + ":00", endTimeStr + ":00", TimeUtil.FORMAT_HHmmSS);

                    if (!isInRange) {
                        String errorMsg = MessageUtil.getErrorMsg(ErrorConst.ORGAN_FASTREDEEM_CHANGCHENG_NOT_IN_SUPPORT_TIME
                            , startTimeStr, endTimeStr);

                        result = new BaseResult();
                        result.setSuccess(false)
                            .setErrorCode(ErrorConst.ORGAN_FASTREDEEM_CHANGCHENG_NOT_IN_SUPPORT_TIME)
                            .setErrorMessage(errorMsg);

                        return new ResponseEntity<>(result, HttpStatus.OK);
                    }
                }


            }
        } else { // 个人

        }
        boolean hasDayDealLimit = false, hasDayDealCountLimit = false;
        //宝盈T+0：
        // 个人用户快赎：单笔限额5万，单日上限200万，次数不限；
        // 机构不支持快赎；

        // 金鹰T+0 长城t+0
        // a) 个人用户快赎：单笔限额200万，单日上限200万，单日次数限制10次
        // b) 机构用户快赎：单笔限额1000万，单日上限5000万，单日次数限制5次
        if (FundUtil.isBaoYingT0AB(fundCode) || FundUtil.isJinYingT0AB(fundCode) ||
            FundUtil.isChangChengT0AB(fundCode)) {

            String str;
            Lookup lookup;

            /*if (FundUtil.isBaoYingT0AB(fundCode)) {
                lookup = lookupService.getLookup(RuleConstant.T0FUND_BAOYING_CONFIG);
            } else {
                lookup = lookupService.getLookup(RuleConstant.RULE_LOOKUP_TYPE_T0FUND, fundCode);
            }*/

            lookup = lookupService.getLookup(RuleConstant.RULE_LOOKUP_TYPE_T0FUND, fundCode);

            str = lookup.getComponentValue();

            //TODO 单笔限额
            String maxSingleDealStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(),
                RuleConstant.FIELD_SINGLE_DEAL_LIMIT);
            if (StringUtil.isNotEmpty(maxSingleDealStr)) {
                if ("-1".equals(maxSingleDealStr)) { // 不做校验
                } else {
                    if (shares.compareTo(new BigDecimal(maxSingleDealStr)) > 1) {
                        String errorMsg = MessageUtil.getErrorMsg(ErrorConst.WALLET_HAS_REACH_MAX_SINGLE_DEAL
                            , maxSingleDealStr);

                        result = new BaseResult();
                        result.setSuccess(false)
                            .setErrorCode(ErrorConst.WALLET_HAS_REACH_MAX_SINGLE_DEAL)
                            .setErrorMessage(errorMsg);

                        return new ResponseEntity<>(result, HttpStatus.OK);
                    }
                }
            }

            //TODO 单日上限
            String maxDayDealStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(), RuleConstant.FIELD_DAY_LIMIT);
            if (StringUtil.isNotEmpty(maxDayDealStr)) {
                if ("-1".equals(maxDayDealStr)) {// 不做校验
                } else {
                    hasDayDealLimit = true;

                    BigDecimal currentDayDeal = walletService.getFastRedeemDayUsedMoney(userId, brandsType);
                    BigDecimal finalDeal      = currentDayDeal.add(shares);
                    if (finalDeal.compareTo(new BigDecimal(maxDayDealStr)) > 1) {
                        String errorMsg = MessageUtil.getErrorMsg(ErrorConst.WALLET_HAS_REACH_MAX_DAY_DEAL
                            , maxDayDealStr);

                        result = new BaseResult();
                        result.setSuccess(false)
                            .setErrorCode(ErrorConst.WALLET_HAS_REACH_MAX_DAY_DEAL)
                            .setErrorMessage(errorMsg);

                        return new ResponseEntity<>(result, HttpStatus.OK);
                    }

                }
            }

            //TODO 单日交易限制次数
            String maxDayDealCountStr = LookupUtil.getT0FieldValueStr(str, user.getIsOrg(),
                RuleConstant.FIELD_DAY_DEAL_COUNT_LIMIT);

            if (StringUtil.isNotEmpty(maxDayDealCountStr)) {
                if ("-1".equals(maxDayDealCountStr)) { // 不做校验
                } else {
                    hasDayDealCountLimit = true;
                    int currentCount = walletService.getFastRedeemCountInCurrentDay(userId, brandsType);
                    if (currentCount >= Integer.valueOf(maxDayDealCountStr)) {
                        String errorMsg = MessageUtil.getErrorMsg(ErrorConst.WALLET_HAS_REACH_MAX_REDEEM_TIME);

                        result = new BaseResult();
                        result.setSuccess(false)
                            .setErrorCode(ErrorConst.WALLET_HAS_REACH_MAX_REDEEM_TIME)
                            .setErrorMessage(errorMsg);

                        return new ResponseEntity<>(result, HttpStatus.OK);
                    }
                }
            }

        }

        // 验证输入
        result = tradeValidation.validateFastRedeem(bankAccount, paymentType, fundName, fundCode, shares, tradePassword,
            token, applyNo, sign, userId, tradeAcco);
        if (result != null) {
            return new ResponseEntity<>(result, HttpStatus.OK);
        }

        // 获取份额类别
        ShareTypeModel shareTypeModel = queryService.getShareType(fundCode);
        if (shareTypeModel == null || StringUtil.isEmpty(shareTypeModel.getShareType())) {
            result = new BaseResult();
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_SHARE_TYPE_FIND, null));
            return new ResponseEntity<>(result, HttpStatus.OK);
        }

        // 获取份额类别
        String shareType = shareTypeModel.getShareType();

        UserSession userSession = userSessionDao.getEntityByToken(token);


        // 调用接口
        result = organTradeService.fastRedeemOrgan(userId, userSession.getChannelId(), paymentType, tradePassword, fundCode,
            shareType, shares, bankAccount, fundName, applyNo, tradeAcco,pId);

        // 失败
        if (!result.getSuccess()) {
            if (StringUtil.isEmpty(result.getErrorMessage())) {
                result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
            }
        } else {
            if (FundUtil.isJinYingT0AB(fundCode) || FundUtil.isChangChengT0AB(fundCode)) {
                if (hasDayDealCountLimit) { // 增加交易次数
                    walletService.increaseFastRedeemCountInCurrentDay(userId, brandsType);
                }
                if (hasDayDealLimit) { // 增加交易金额
                    walletService.increaseFastRedeemDayUsedMoney(userId, brandsType, shares);
                }
            }
        }

        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    @Loggable
    @RequestMapping(value = "/undo", method = RequestMethod.POST)
    public BaseResult undo(HttpServletRequest request, HttpServletResponse response,
                           @RequestParam String originalApplyNo, @RequestParam String tradePassword,
                           @RequestParam String applyNo, @RequestHeader(GlobalConstant.HEADER_AUTH_TOKEN) String token) {
        log.info("undo request, originalApplyNo:" + originalApplyNo + ", applyNo:" + applyNo);
        BaseResult result = null;

        // 获取channel Id
        UserSession userSession = userSessionDao.getEntityByToken(token);
        // 判断Session是否存在
        if (userSession == null) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_LOGIN_IN_OTHER_PLACE);
            return result;
        }

        // 调用接口
        result = organTradeService.organUndoReal(UserUtil.getLoginUserId(), userSession.getChannelId(), originalApplyNo, tradePassword,UserUtil.getProfileId());
        if (!result.getSuccess() && StringUtil.isEmpty(result.getErrorMessage())) {
            result.setErrorMessage(MessageUtil.getErrorMessage(result.getErrorCode(), null));
        }

        return result;
    }

}
